﻿using System;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Interactivity;
using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MugenMvvmToolkit.Behaviors;
using MugenMvvmToolkit.Interfaces;
using MugenMvvmToolkit.Models;
using MugenMvvmToolkit.ViewModels;
using MugenMvvmToolkitTest.TestInfrastructure;
using Should;

namespace MugenMvvmToolkitTest.Behaviors
{
    [TestClass]
    public class EventManagerTest
    {
        [TestMethod]
        public void TestInvokeWithoutParameter()
        {
            var eventManager = new EventToCommand();
            var button = new Button();
            ((IAttachedObject)eventManager).Attach(button);
            var vm = new TestViewModel();


#if SILVERLIGHT
            eventManager.Command = vm.SimpleCommand;
#else
            var binding = new Binding
                              {
                                  Source = vm.SimpleCommand
                              };
            BindingOperations.SetBinding(eventManager, EventToCommand.CommandProperty, binding);
#endif

            eventManager.Execute();
            vm.SimpleCommandExecuted.ShouldBeTrue();
            vm.CommandParameters.CmdParameter.ShouldBeNull();
            vm.CommandParameters.EventParameter.ShouldBeNull();
        }

        [TestMethod]
        public void TestInvokeWithCommandParameter()
        {
            var eventManager = new EventToCommand();
            var button = new Button();
            ((IAttachedObject)eventManager).Attach(button);

            const string testParameter = "testParameter";

            var vm = new TestViewModel();
#if SILVERLIGHT
            eventManager.Command = vm.SimpleCommand;
#else
            var binding = new Binding
                              {
                                  Source = vm.SimpleCommand
                              };
            BindingOperations.SetBinding(eventManager, EventToCommand.CommandProperty, binding);
#endif

            eventManager.CommandParameter = testParameter;
            eventManager.Execute();

            vm.SimpleCommandExecuted.ShouldBeTrue();
            vm.CommandParameters.CmdParameter.ShouldEqual(testParameter);
            vm.CommandParameters.EventParameter.ShouldBeNull();
        }

        [TestMethod]
        public void TestInvokeWithEventAndCommandParameter()
        {
            var eventManager = new EventToCommand();
            var button = new Button();
            ((IAttachedObject)eventManager).Attach(button);

            const string testParameter = "testParameter";
            var eventParam = new EventArgs();

            var vm = new TestViewModel();

#if SILVERLIGHT
            eventManager.Command = vm.SimpleCommand;
#else
            var binding = new Binding
                              {
                                  Source = vm.SimpleCommand
                              };
            BindingOperations.SetBinding(eventManager, EventToCommand.CommandProperty, binding);
#endif

            eventManager.CommandParameter = testParameter;
            eventManager.Execute(eventParam);

            vm.SimpleCommandExecuted.ShouldBeTrue();
            vm.CommandParameters.CmdParameter.ShouldEqual(testParameter);
            vm.CommandParameters.EventParameter.ShouldEqual(eventParam);
        }

        [TestMethod]
        public void TestEnabledElement()
        {
            var eventManager = new EventToCommand
                                   {
                                       IsChangeEnabledState = true
                                   };
            var button = new Button();
            ((IAttachedObject)eventManager).Attach(button);
            var vm = new TestViewModel();
#if SILVERLIGHT
            eventManager.Command = vm.SimpleCommand;
#else
            var binding = new Binding
            {
                Source = vm.SimpleCommand
            };
            BindingOperations.SetBinding(eventManager, EventToCommand.CommandProperty, binding);
#endif
            button.IsEnabled.ShouldBeTrue();
            vm.CanExecute = o => false;
            vm.SimpleCommand.RaiseCanExecuteChanged();
            button.IsEnabled.ShouldBeFalse();

            vm.CanExecute = o => true;
            vm.SimpleCommand.RaiseCanExecuteChanged();
            button.IsEnabled.ShouldBeTrue();
        }

        [TestMethod]
        public void TestCanExecuteCmd()
        {
            var eventManager = new EventToCommand();
            var button = new Button();
            ((IAttachedObject)eventManager).Attach(button);
            var vm = new TestViewModel();

#if SILVERLIGHT
            eventManager.Command = vm.SimpleCommand;
#else
            var binding = new Binding
            {
                Source = vm.SimpleCommand
            };
            BindingOperations.SetBinding(eventManager, EventToCommand.CommandProperty, binding);
#endif
            vm.CanExecute = o => false;
            eventManager.Execute();
            vm.SimpleCommandExecuted.ShouldBeFalse();

            vm.CanExecute = o => true;
            eventManager.Execute();
            vm.SimpleCommandExecuted.ShouldBeTrue();
        }

        [TestMethod]
        public void TestCanExecuteCondition()
        {
            var cond = new TestCondition();
            var eventManager = new EventToCommand();
            var button = new Button();
            ((IAttachedObject)eventManager).Attach(button);
            var vm = new TestViewModel();

            const string testParameter = "testParameter";
            var eventParam = new EventArgs();
            eventManager.CommandParameter = testParameter;
#if SILVERLIGHT
            eventManager.Command = vm.SimpleCommand;
#else
            var binding = new Binding
            {
                Source = vm.SimpleCommand
            };
            BindingOperations.SetBinding(eventManager, EventToCommand.CommandProperty, binding);
#endif
            eventManager.EventCondition = cond;

            vm.CanExecute = o => true;
            cond.IsCanExecute = false;
            eventManager.Execute(eventParam);
            vm.SimpleCommandExecuted.ShouldBeFalse();
            cond.Parameter.CmdParameter.ShouldEqual(testParameter);
            cond.Parameter.EventParameter.ShouldEqual(eventParam);

            vm.CanExecute = o => true;
            cond.IsCanExecute = true;
            eventManager.Execute(eventParam);
            vm.SimpleCommandExecuted.ShouldBeTrue();
            cond.Parameter.CmdParameter.ShouldEqual(testParameter);
            cond.Parameter.EventParameter.ShouldEqual(eventParam);
        }
    }

    public class TestCondition : ICondition
    {
        #region Properties

        public CommandParameter Parameter { get; set; }

        public bool IsCanExecute { get; set; }

        #endregion

        #region Implementation of ICondition

        /// <summary>
        ///     Defines the method that determines whether the condition can execute in its current state.
        /// </summary>
        /// <returns>
        ///     true if this condition can be executed; otherwise, false.
        /// </returns>
        /// <param name="parameter">Data used by the condition. If the condition does not require data to be passed, this object can be set to null. </param>
        public bool CanExecute(object parameter)
        {
            Parameter = (CommandParameter)parameter;
            return IsCanExecute;
        }

        #endregion
    }

    public class TestViewModel
    {
        public CommandParameter CommandParameters;

        public Predicate<object> CanExecute = o => true;

        public TestViewModel()
        {
            SimpleCommand = new RelayCommand(o =>
                                                 {
                                                     CommandParameters = (CommandParameter) o;
                                                     SimpleCommandExecuted = true;
                                                 }, CanExecuteCmd, null,
                                             new TestThreadManager
                                                 {
                                                     ImmediateInvokeAsync = true,
                                                     ImmediateInvokeInUi = true,
                                                     ImmediateInvokeInUiSynchronous = true
                                                 }, null);
        }

        public bool SimpleCommandExecuted { get; set; }

        public RelayCommand SimpleCommand { get; private set; }

        private bool CanExecuteCmd(object obj)
        {
            return CanExecute(obj);
        }
    }
}